<!doctype html>
<!--
@license
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<html>
<head>
  <meta charset="utf-8">
  <script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
  <script src="../../../web-component-tester/browser.js"></script>
  <link rel="import" href="../../polymer.html">
  <link rel="import" href="configure-elements.html">
</head>
<body>

  <x-configure-value></x-configure-value>

  <x-configure-value content="attr" object='{"foo": "obj-attr"}'></x-configure-value>

  <x-configure-host></x-configure-host>

  <x-configure-host content="attr"></x-configure-host>

<script>

  function testValueAndChangeHandler(e, value) {
    assert.equal(e.content, value, 'Property does not equal configured value');
    assert.equal(e.changeHandlerCount, 1, 'property `change` Change handler not run when default value set');
    assert.equal(e.objectChangeHandlerCount, 1, 'property `object` Change handler not run when default value set');
  }

  function testConfigure(e, value, objectValue) {
    testValueAndChangeHandler(e, value);
    assert.equal(e.object.foo, objectValue);
    assert.equal(e.$.content.textContent, value, 'Bound value not propagated to dom');
  }

  function testConfigureHost(e, value) {
    testValueAndChangeHandler(e, value);
    e = e.$.child;
    testValueAndChangeHandler(e, value);
    e = e.$.gchild;
    testValueAndChangeHandler(e, value);
    assert.equal(e.$.content.textContent, value, 'Bound value not propagated to dom');
  }

  suite('configure', function() {

    test('value set in properties initializes correctly', function() {
      var e = document.querySelector('x-configure-value');
      testConfigure(e, 'default', 'obj-default');
    });

    test('attribute overrides value set in properties', function() {
      var e = document.querySelector('x-configure-value[content]');
      testConfigure(e, 'attr', 'obj-attr');
    });

    test('configured values initialize and propagates', function() {
      var e = document.querySelector('x-configure-host');
      testConfigureHost(e, 'host');
    });

    test('negated value configured correctly', function() {
      var e = document.querySelector('x-configure-host');
      assert.equal(e.$.child.negatedContent, false);
      assert.isTrue(e.$.child.negatedContentChanged.calledOnce, 'negated content not changed exactly once');
    });

    test('compound effect resulting value set once', function() {
      var e = document.querySelector('x-configure-host');

      assert.equal(e.$.child.compoundInput, 'a simple host');
      assert.isTrue(e.$.child.compoundInputChanged.calledOnce, 'compound content not changed exactly once');
    });

    test('attribute overrides configured values and propagates', function() {
      var e = document.querySelector('x-configure-host[content]');
      testConfigureHost(e, 'attr');
    });

    test('property changed in change handler of another not stomped by default', function() {
      var e = document.querySelector('x-configure-value');
      assert.equal(e.stomp, 10);
    });

    test('read-only property initialized to default value', function() {
      var e = document.querySelector('x-configure-value');
      assert.equal(e.readOnly, 'default');
    });

    test('attribute bindings to properties without effects not configured', function() {
      var e = document.querySelector('x-configure-host');
      assert.equal(e.$.child.getAttribute('attr'), 'attrValue');
      assert.equal(e.$.child.attr, undefined);
    });

    test('attribute bindings to properties with effects configured', function() {
      var e = document.createElement('x-configure-host');

      assert.equal(e.$.child.getAttribute('attr-dash'), 'attrValue');
      assert.notProperty(e.$.child, 'attr-dash');
      assert.equal(e.$.child.attrDash, 'attrValue');
      assert.isTrue(e.$.child.attrDashChanged.calledOnce);
      assert.equal(e.$.child.attrDashChanged.getCall(0).args[0], 'attrValue');

      assert.equal(e.$.child.getAttribute('attr-number'), '42');
      assert.notProperty(e.$.child, 'attr-number');
      assert.strictEqual(e.$.child.attrNumber, 42);
      assert.isTrue(e.$.child.attrNumberChanged.calledOnce);
      assert.strictEqual(e.$.child.attrNumberChanged.getCall(0).args[0], 42);

      assert.equal(e.$.child.hasAttribute('attr-boolean'), false);
      assert.notProperty(e.$.child, 'attr-boolean');
      assert.strictEqual(e.$.child.attrBoolean, false);
      assert.isTrue(e.$.child.attrBooleanChanged.calledOnce);
      assert.strictEqual(e.$.child.attrBooleanChanged.getCall(0).args[0], false);
    });

    test('bindings to properties without effects configured', function() {
      var e = document.createElement('x-configure-host');
      assert.isTrue(e.$.simple.hasPropertyAtReadyTime, 'property value not configured and therefore not set at ready time');
    });

    test('pre-register property assignment does not break getters and setters', function() {
      // don't test if __proto__ is polyfilled (IE10); cannot be fixed in this case.
      if (Polymer.Settings.usePolyfillProto) {
        return;
      }
      var x = document.createElement('x-late-register');
      document.body.appendChild(x);
      // set property
      x.shouldChange = '1';
      // now register element
      Polymer({
        is: 'x-late-register',
        properties: {
          shouldChange : {
            observer: 'shouldChangeCallback',
            type: String
          }
        },
        shouldChangeCallback: function() {
          this.textContent = this.shouldChange;
        }
      });
      CustomElements.takeRecords();
      assert.equal(x.shouldChange, '1');
      assert.equal(x.shouldChange, x.textContent);
      x.shouldChange = '2';
      assert.equal(x.shouldChange, '2');
      assert.equal(x.shouldChange, x.textContent);
      document.body.removeChild(x);
    });

    test('setting properties in created works with configuration', function() {
      // don't test if __proto__ is polyfilled (IE10); cannot be fixed in this case.
      if (Polymer.Settings.usePolyfillProto) {
        return;
      }
      var x = document.createElement('x-late-register2');
      document.body.appendChild(x);
      // now register element
      Polymer({
        is: 'x-late-register2',
        properties: {
          a: {
            type: Number
          },
          b: {
            value: function() {
              return this.a * 2;
            }
          }
        },
        created: function() {
          this.a = 1;
        }
      });
      CustomElements.takeRecords();
      assert.equal(x.b, 2);
      document.body.removeChild(x);
    });

    test('lazy upgrade binding use cases', function() {
      // don't test if __proto__ is polyfilled (IE10); cannot be fixed in this case.
      if (Polymer.Settings.usePolyfillProto) {
        return;
      }
      var el = document.createElement('x-config-lazy-host');
      document.body.appendChild(el);
      Polymer(window.XConfigLazy);
      assert.equal(el.$.lazy.noEffectProp, 1);
      assert.equal(el.$.lazy.defaultUsesNoEffectProp, 2);
      assert.equal(el.$.lazy.prop, 'foo');
      assert.isTrue(el.$.lazy.propChanged.calledOnce);
      assert.equal(el.$.lazy.readOnlyProp, 'readOnly');
      assert.equal(el.$.lazy.hadAttrProp, 'foo');
      assert.isTrue(el.$.lazy.hadAttrPropChanged.calledOnce);
      document.body.removeChild(el);
    });

  });

</script>
</body>
</html>
